local Human = require("core.Human")
local DB = require("common.DB")
local LuaMongo = _G.lua_mongo
local OfflinePkDefine = require("offlinepk.Define")
local RoleDBLogic = require("role.RoleDBLogic")
local RoleFFI = require("role.RoleFFI")
local Msg = require("core.Msg")
local InnerDataManager = require("innerdata.InnerDataManagerFW")
local InnerDefine = require("innerdata.Define")
local CopyDefine =require("copy.Define")
local CopyCommon      = require("copy.CopyCommon")
local OfflinePkExcel = require("excel.OfflinePk")
local ItemDefine = require("bag.ItemDefine")
local ServerCommonFW = require("serverCommon.ServerCommonFW")
local MailLogicFW =require("mail.MailLogicFW")
local Lang = require("common.Lang")
local Grid = require("bag.Grid")
local OperateActFW = require("activity.OperateActFW")
local OperateActDefine = require("activity.Define")

TOTAL_RANK = TOTAL_RANK or 0    --当前最后排名
TOP_RANK_LIST = TOP_RANK_LIST or {} -- 排行榜

MOSNTER_RANK_UUID = MOSNTER_RANK_UUID or 0 

MONSTER_RANK = MONSTER_RANK or {}  -- "monster uuid -> rank"
RANK_MONSTER = RANK_MONSTER or {}  -- "rank -> monster uuid"

TOP_RANK_CNT = 100
local query = {}
local charFields = {offlinePkRank = 1, name = 1, zhandouli = 1, lv = 1}
local logFields  = {offlinePkRank = 1, offlinePkLogs = 1, offlinePkLogsLen = 1}
function modifyRank()
    LuaMongo.find(DB.db_char,{["$query"]={offlinePkRank={["$gte"]=1}},["$orderby"]={offlinePkRank=1}},{offlinePkRank=1})
    local a = {}
    local m = {}
    while true do
        local t = {}
        if not LuaMongo.next(DB.db_char, t) then
            break
        end
        if not a[t.offlinePkRank] then
            a[t.offlinePkRank] = 1         
        else 
            for i = t.offlinePkRank+1, t.offlinePkRank + 500 do
                if not a[i] then
                    a[i] = 1
                    t.offlinePkRank = i
                    m[#m+1] = t
                    break
                end
            end
        end
    end
    print("modify:", #m)
    for i = 1, #m do
        RoleDBLogic.saveRoleSset(m[i])
    end    
end
function init()
    local reader = ServerCommonFW.onGetServerCommonDB()
    if not reader or reader.ServerOfflinePkTotalRank == nil then
        TOTAL_RANK = 500
    else
        TOTAL_RANK = reader.ServerOfflinePkTotalRank
    end
    modifyRank()
    LuaMongo.find(DB.db_char,{["$query"]={offlinePkRank={["$gte"]=1,["$lte"] = TOP_RANK_CNT}},["$orderby"]={offlinePkRank=1}},charFields,TOP_RANK_CNT)
    while true do
        local t = {}
        if not LuaMongo.next(DB.db_char, t) then
            break
        end
        TOP_RANK_LIST[t.offlinePkRank] = t
        TOP_RANK_LIST[t.offlinePkRank].uuid = t._id
    end
    
    for i = 1, TOP_RANK_CNT do
        if TOP_RANK_LIST[i] == nil then
            TOP_RANK_LIST[i] = {}
            TOP_RANK_LIST[i].uuid = createMonsterRank(i)            
            TOP_RANK_LIST[i].name= "群雄霸主"..i
            TOP_RANK_LIST[i].zhandouli = 5000
            TOP_RANK_LIST[i].lv = 100
        end
    end
        
    print("TOP_RANK_LIST:",  TOTAL_RANK)
end

function createMonsterRank(rank)
    MOSNTER_RANK_UUID = MOSNTER_RANK_UUID + 1
    local uuid = "muuid"..MOSNTER_RANK_UUID    
    MONSTER_RANK[uuid] = rank
    RANK_MONSTER[rank] = uuid
    return uuid
end

-- 根据排名得到角色DB数据
local function getDBByOfflinePKRank(rank)
    for uuid, human in pairs(Human.onlineUuid) do
        if human.db.offlinePkRank == rank then
              local db = RoleFFI.get_default_db()
              RoleFFI.copy_ffi_to_db(human.db, db)
              return db
        end
    end
    query.offlinePkRank = rank
    local data = {}
    LuaMongo.find(DB.db_char, query)
    if not LuaMongo.next(data) then
        return
    end
    return data
end 
local db_data= {ServerOfflinePkTotalRank = 1}
function checkOfflinePkRank(human)
    if human.db.offlinePkRank > 0 then
        return
    end
    if human.db.lv >= OfflinePkDefine.OFFLINE_PK_LOG_MAX then
        TOTAL_RANK = TOTAL_RANK + 1
        human.db.offlinePkRank = TOTAL_RANK
        human.db.offlinePkRewardRank = TOTAL_RANK
        if human.db.offlinePkHistoryRank <= 0 then
          human.db.offlinePkHistoryRank = TOTAL_RANK
        end
        db_data.ServerOfflinePkTotalRank = TOTAL_RANK
        ServerCommonFW.upDateServerCommon(db_data)
    end
end


local function canJoin(value, without, len)
    for i = 1, len do
        if without[i] == value then
            return 
        end
    end
    return true
end 


local function getPlayerList(myrank)
    local list = {}
    local listLen = 0
    if myrank < 6 then   --5名以内
        for i = 1, 6 do
            if i > TOTAL_RANK then
                break
            end
            if i ~= myrank then
                listLen = listLen + 1
                list[listLen] = i
            end
        end
     else
        local config
        for i = 1, #OfflinePkExcel.pkSelect do
            local conf = OfflinePkExcel.pkSelect[i]
            if myrank >= conf.minRank and (conf.maxRank == -1 or myrank <= conf.maxRank) then
                config = conf
                break
            end
        end
        for i = 1, 5 do
            local r = math.random(myrank-config.range, myrank-1)
            if canJoin(r, list, listLen) then
                listLen = listLen + 1
                list[listLen] = r
            end
        end
        if listLen < 5 then
            for i = myrank-1, myrank-config.range, -1 do
                if canJoin(i, list, listLen) then
                    listLen = listLen + 1
                    list[listLen] = i
                    if listLen == 5 then
                        break
                    end
                end
            end
        end
    end
    return list
end
function sendPkPlayerList(human)
    local msg = Msg.gc.GC_OFFLINE_PK_PLAYER
    local info = msg.players
    if human.offlinePkPlayerList == nil then
        human.offlinePkPlayerList = getPlayerList(human.db.offlinePkRank)
    end
    local list = human.offlinePkPlayerList
    info[0] = #list
    for i = 1, #list do
        local db = getDBByOfflinePKRank(list[i])
        if db then
          info[i].uuid = db._id
          info[i].name = db.name
          info[i].zhandouli = db.zhandouli
          Human.makeViewInfo(info[i].viewInfo, db.sex,Human.getRealBodyInfo(db))          
        else
          local uuid = RANK_MONSTER[list[i]]
          if not uuid then
              uuid = createMonsterRank(list[i])              
          end
          info[i].uuid = uuid
          info[i].name = "群雄霸主"..list[i]
          info[i].zhandouli = 5000
          Human.makeViewInfo(info[i].viewInfo, 0, OfflinePkDefine.getMasterViewInfo(list[i]))
        end
        info[i].rank = list[i]
    end    
    Msg.send(msg, human.fd)
end

function sendSelfPkInfo(human)
    local msg = Msg.gc.GC_OFFLINE_PK_QUERY
    msg.myRank = human.db.offlinePkRank
    msg.myZhandouli = human.db.zhandouli
    msg.curCnt = CopyCommon.getCopyEnterCount(human, CopyDefine.COPY_OFFLINE_PK_ID)
    msg.maxCnt = CopyCommon.getCopyMaxEnterCount(human, CopyDefine.COPY_OFFLINE_PK_ID)
    msg.leftTime = OfflinePkDefine.OFFLINE_PK_COOLDOWN - (os.time() - human.db.offlinePkTime) 
    if msg.leftTime < 0 then
        msg.leftTime = 0
    end
    msg.canGetReward = human.db.offlinePkRewardRank >0 and 1 or 0
    msg.rewardTips = getRewardDesc(human)
    msg.historyRank = human.db.offlinePkHistoryRank
    Msg.send(msg, human.fd)
end

--加日志
local function addLog(human, targetUuid,targetName,rank, win, result)
    local log
    if human.db.offlinePkLogsLen < OfflinePkDefine.OFFLINE_PK_LOG_MAX then
        log = human.db.offlinePkLogs[human.db.offlinePkLogsLen]
        human.db.offlinePkLogsLen = human.db.offlinePkLogsLen + 1
    else
        for i = 1, human.db.offlinePkLogsLen -1 do
          RoleFFI.copy_array_element(human.db.offlinePkLogs, i-1, i, 'struct offlinepk_log')
        end
        log = human.db.offlinePkLogs[human.db.offlinePkLogsLen-1]
    end
    log.name = targetName
    log.win  = win and 1 or 0
    log.rank = rank
    log.result = result
    log.active = 1
    log.time = os.time()    
    if string.len(targetUuid) < 20 then
        return
    end
    if result == OfflinePkDefine.PK_RANK_UP then
       result = OfflinePkDefine.PK_RANK_DOWN
    end
    local targetHuman = Human.onlineUuid[targetUuid] --被PK日志
    if targetHuman then
        if targetHuman.db.offlinePkLogsLen < OfflinePkDefine.OFFLINE_PK_LOG_MAX then
            log = targetHuman.db.offlinePkLogs[targetHuman.db.offlinePkLogsLen]
            targetHuman.db.offlinePkLogsLen = targetHuman.db.offlinePkLogsLen + 1
        
        else
            for i = 1, targetHuman.db.offlinePkLogsLen -1 do
              RoleFFI.copy_array_element(targetHuman.db.offlinePkLogs, i-1, i, 'struct offlinepk_log')
            end
            log = targetHuman.db.offlinePkLogs[targetHuman.db.offlinePkLogsLen-1]
        end
        log.name = human.name
        log.win = win and 0 or 1
        log.rank = targetHuman.db.offlinePkRank
        log.result = result
        log.active = 0
        log.time = os.time()    
    else
        local db = RoleDBLogic.getDbByUuid(targetUuid, logFields)
        if db.offlinePkLogsLen < OfflinePkDefine.OFFLINE_PK_LOG_MAX then
            if db.offlinePkLogs[db.offlinePkLogsLen] == nil then
                db.offlinePkLogs[db.offlinePkLogsLen]  = {}
            end
            log = db.offlinePkLogs[db.offlinePkLogsLen]
            db.offlinePkLogsLen = db.offlinePkLogsLen + 1
        else
            for i = 1, db.offlinePkLogsLen - 1 do
                db.offlinePkLogs[i-1] = db.offlinePkLogs[i]
            end
            log = db.offlinePkLogs[db.offlinePkLogsLen-1]
        end
        log.name = human.name
        log.win = win and 0 or 1
        log.rank = db.offlinePkRank
        log.result = result
        log.active = 0        
        log.time = os.time()    
        db.offlinePkRank = nil
        db._id = targetUuid
        RoleDBLogic.saveRoleSset(db)
    end   
end

bindYuanbaoGrid = nil
--通知结果
function sendPkReward(human, win, result)
    local msg = Msg.gc.GC_OFFLINE_PK_RESULT
    msg.win = win and 1 or 0
    msg.result  = result
    msg.rank = human.db.offlinePkRank
    local reward 
    if win then
      reward = OfflinePkExcel.pkReward[1].win
    else
      reward = OfflinePkExcel.pkReward[1].fail
    end
    local cnt = #reward
    if cnt > 4 then cnt = 4 end
    for i = 1, cnt do
        msg.reward[i].item_name = ItemDefine.getValue(reward[i][1], "name")
        msg.reward[i].item_cnt  = reward[i][2]
    end
    msg.reward[0] = cnt
    msg.bindYuanbao = 0
    if human.db.offlinePkRank < human.db.offlinePkHistoryRank then
        local diff = human.db.offlinePkHistoryRank
        if diff > 500 then
            diff = 500
        end
        diff = diff - human.db.offlinePkRank
        if diff < 0 then
            diff = 0
        end
        human.db.offlinePkHistoryRank = human.db.offlinePkRank
        local conf
        for k,v in pairs(OfflinePkExcel.rewardRank) do
          if v.minRank <= human.db.offlinePkRank and (v.maxRank == -1 or human.db.offlinePkRank <= v.maxRank) then
            conf = v
            break
          end
        end
        if not conf then
          conf = OfflinePkExcel.rewardRank[#OfflinePkExcel.rewardRank]
        end
        msg.bindYuanbao = diff * conf.historyReward
        if msg.bindYuanbao > 0 then
          if not bindYuanbaoGrid then
            bindYuanbaoGrid = {}
            Grid.create(bindYuanbaoGrid,ItemDefine.ITEM_ID_BIND_YUANBAO,msg.bindYuanbao)
          end 
          bindYuanbaoGrid.cnt = msg.bindYuanbao
          MailLogicFW.addSystemMessage(human._id, Lang.OFFLINE_PK_MAIL_TITLE, string.format(Lang.OFFLINE_PK_MAIL_CONTENT,msg.bindYuanbao), {bindYuanbaoGrid})
        end
    end
    
    Msg.send(msg, human.fd)
end


--得到奖励串
function getRewardDesc(human)
   local conf
   for k,v in pairs(OfflinePkExcel.rewardRank) do
      if v.minRank <= human.db.offlinePkRank and (v.maxRank == -1 or human.db.offlinePkRank <= v.maxRank) then
          conf = v
          break
      end
   end
   if not conf then
      conf = OfflinePkExcel.rewardRank[#OfflinePkExcel.rewardRank]
   end
   local str = ""
   for i = 1, #conf.reward do
      str = str .. ItemDefine.getValue(conf.reward[i][1], "name").."x"..conf.reward[i][2].." "
   end
   return str
end

--开始
function onPKStart(human, type, data)
    human.offlinepk_target = data.uuid
end

local function saveRank(uuid, rank)
    local db = {}
    db._id = uuid        
    db.offlinePkRank = rank
    RoleDBLogic.saveRoleSset(db)
end


--完成
function onPKFinish(human, type, data)
    if data.uuid == nil then
        return
    end
    if human.offlinepk_target ~= data.uuid then
        return
    end   
    local result = OfflinePkDefine.PK_RANK_KEEP
    if string.len(data.uuid) < 20 then --打群雄霸主
        local name = "群雄霸主"..MONSTER_RANK[data.uuid]
        if data.win == 1 and human.db.offlinePkRank > MONSTER_RANK[data.uuid] then          
          local tmp = human.db.offlinePkRank
          RANK_MONSTER[MONSTER_RANK[data.uuid]] = nil
          human.db.offlinePkRank = MONSTER_RANK[data.uuid]
          RANK_MONSTER[tmp] = data.uuid     
          MONSTER_RANK[data.uuid] = tmp           
          if human.db.offlinePkRank < TOP_RANK_CNT then
            if TOP_RANK_LIST[tmp] then
                TOP_RANK_LIST[tmp].uuid = TOP_RANK_LIST[human.db.offlinePkRank].uuid
                TOP_RANK_LIST[tmp].name = TOP_RANK_LIST[human.db.offlinePkRank].name
                TOP_RANK_LIST[tmp].zhandouli = TOP_RANK_LIST[human.db.offlinePkRank].zhandouli
                TOP_RANK_LIST[tmp].lv = TOP_RANK_LIST[human.db.offlinePkRank].lv
            end
            TOP_RANK_LIST[human.db.offlinePkRank].uuid = human._id
            TOP_RANK_LIST[human.db.offlinePkRank].name = human.name
            TOP_RANK_LIST[human.db.offlinePkRank].zhandouli = human.db.zhandouli
            TOP_RANK_LIST[human.db.offlinePkRank].lv = human.db.lv
          end 
          result = OfflinePkDefine.PK_RANK_UP
          human.offlinePkPlayerList = nil
          saveRank(human._id, human.db.offlinePkRank)
        end        
        human.db.offlinePkTime = os.time()
        addLog(human, data.uuid, name, human.db.offlinePkRank, data.win == 1, result)
        human.offlinepk_target = nil
        sendPkReward(human, data.win == 1, result)
        
        return
    end
    local win
    local targetHuman = Human.onlineUuid[data.uuid]
    local db
    local name
    if targetHuman then
        name = targetHuman.name
    else
        db = RoleDBLogic.getDbByUuid(data.uuid, charFields)
        name = db.name
    end
    
    if data.win == 1 then
        --交换排名
        local tmp = human.db.offlinePkRank        
        if targetHuman then
            if targetHuman.db.offlinePkRank < tmp then
                human.db.offlinePkRank = targetHuman.db.offlinePkRank
                targetHuman.db.offlinePkRank = tmp 
                result = OfflinePkDefine.PK_RANK_UP
                human.offlinePkPlayerList = nil
                targetHuman.offlinePkPlayerList = nil
                saveRank(human._id, human.db.offlinePkRank)
                saveRank(targetHuman._id, human.db.offlinePkRank)
            end
        else            
            if db.offlinePkRank < tmp then
                human.db.offlinePkRank = db.offlinePkRank
                result = OfflinePkDefine.PK_RANK_UP
                human.offlinePkPlayerList = nil
                saveRank(human._id, human.db.offlinePkRank)
                saveRank(data.uuid, tmp)
            end
        end
        win = true
        
        if human.db.offlinePkRank < TOP_RANK_CNT then
            if TOP_RANK_LIST[tmp] then
                TOP_RANK_LIST[tmp].uuid = TOP_RANK_LIST[human.db.offlinePkRank].uuid
                TOP_RANK_LIST[tmp].name = TOP_RANK_LIST[human.db.offlinePkRank].name
                TOP_RANK_LIST[tmp].zhandouli = TOP_RANK_LIST[human.db.offlinePkRank].zhandouli
                TOP_RANK_LIST[tmp].lv = TOP_RANK_LIST[human.db.offlinePkRank].lv
            end
            TOP_RANK_LIST[human.db.offlinePkRank].uuid = human._id
            TOP_RANK_LIST[human.db.offlinePkRank].name = human.name
            TOP_RANK_LIST[human.db.offlinePkRank].zhandouli = human.db.zhandouli
            TOP_RANK_LIST[human.db.offlinePkRank].lv = human.db.lv
        end
        
    end
    human.db.offlinePkTime = os.time()
    addLog(human, data.uuid, name, human.db.offlinePkRank, win, result)
    human.offlinepk_target = nil
    sendPkReward(human, win, result)
end

function onPKNotify(human, type, data)
    if data and data.decCD then
        human.db.offlinePkTime = 0
    end
    sendSelfPkInfo(human)
end

--玩家进入挑战副本
function onHumanEnterCopy(uuid)
    local human = Human.onlineUuid[uuid]
    if not human or human.offlinepk_target == nil then
        return
    end
    local db
    if string.len(human.offlinepk_target) < 20 then
        db = {_id = human.offlinepk_target, name= "群雄霸主"..MONSTER_RANK[human.offlinepk_target], rank= MONSTER_RANK[human.offlinepk_target]}
    else
        db = RoleDBLogic.getDbByUuid(human.offlinepk_target)
        if not db then
            return
        end
        if db.bag then
            db.bag = nil
            db.store = nil 
            db.cooldown = nil 
            db.familyApplyList = nil
            db.familyShopList = nil
            db.mysteryshopList = nil
            db.prestigeshopList = nil
            db.taskRecord = nil
            db.taskGroup = nil
            db.mysteryPrestigeShopList = nil
            db.mysteryHonorShopList = nil
            db.cowryRecord = nil
            db.actValueRecord = nil
            db.black = nil
            db.enemy = nil
            db.copyTimes = nil
            db.pata_store = nil
            db.reviveNowDataList = nil
            db.offlinePkLogs = nil
        end
    end
    
    InnerDataManager.Send2LInnerData(human, InnerDefine.INNERDATA_TYPE_OFFLINE_PK_GET_DATA, db)    
end


function onNightReward()  --每天21点发奖励
    local conf
    for i = 1, #OfflinePkExcel.rewardRank do
        conf = OfflinePkExcel.rewardRank[i]
        if #conf.reward > 0 and conf.minRank >0 and conf.minRank <= TOP_RANK_CNT then
            local m = conf.maxRank
            if m > TOP_RANK_CNT then
                m = TOP_RANK_CNT
            end
            
            local add = 1
            if OperateActFW.onCheckActIsRunning(OperateActDefine.OPERATEACT_TYPE_GOODPK) then
                add = 2
            end
            local gridlist = {}
            for j = 1, #conf.reward do
                local grid = {}
                Grid.create(grid,conf.reward[j][1],conf.reward[j][2]*add,conf.reward[j][3])
                gridlist[#gridlist + 1] = grid
            end
            for j = conf.minRank, m do
              local uuid = TOP_RANK_LIST[j].uuid
              if string.len(uuid) > 20 then
                MailLogicFW.addSystemMessage(uuid, Lang.OFFLINE_PK_MAIL_TITLE, string.format(Lang.OFFLINE_PK_MAIL_CONTENT1,j), gridlist)
              end              
            end
        end
    end
end

InnerDataManager.Register(InnerDefine.INNERDATA_TYPE_OFFLINE_PK_START,   onPKStart)
InnerDataManager.Register(InnerDefine.INNERDATA_TYPE_OFFLINE_PK_END,onPKFinish)
InnerDataManager.Register(InnerDefine.INNERDATA_TYPE_OFFLINE_PK_DATA, onPKNotify)


